package cn.ronghuanet.user.service.impl;

import cn.ronghuanet.base.constants.BaseConstants;
import cn.ronghuanet.base.exception.BusinessException;
import cn.ronghuanet.base.util.SmsUtil;
import cn.ronghuanet.base.util.StrUtils;
import cn.ronghuanet.base.util.VerifyCodeUtils;
import cn.ronghuanet.base.exception.ResponseCode;
import cn.ronghuanet.base.exception.RonghuaAssert;
import cn.ronghuanet.user.domain.User;
import cn.ronghuanet.user.dto.RegisterSendSmsCodeDTO;
import cn.ronghuanet.user.mapper.UserMapper;
import cn.ronghuanet.user.service.IVerifyCodeService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Override
    public String getRegisterImageCode(String imageCodeKey) throws Exception{
        // 1 创建6位数的随机字符串
        String randomString = StrUtils.getComplexRandomString(6);
        System.out.println(randomString);

        // 2 将生成的随机字符串存入redis,设置5分钟过期时间 以imageCodeKey为key,以随机字符串为value
        redisTemplate.opsForValue().set(imageCodeKey,randomString,5, TimeUnit.MINUTES);

        // 3 根据随机字符串生成图片
        String base64Str = VerifyCodeUtils.VerifyCode(135, 42, randomString);

        // 4 将图片转成base64加密字符串,返回前端
        return base64Str;
    }

    @Override
    public void registerSendSmsCode(RegisterSendSmsCodeDTO dto) {
        // 1 参数校验
        // 1.1 imageCodeKey不能为空
        RonghuaAssert.isNotBlank(dto.getImageCodeKey(), ResponseCode.RESPONSE_CODE_500);

        // 1.2 校验图片验证码是否一致
        // 1.2.1 从redis中获取图片验证码
        String imageCodeByRedis = (String)redisTemplate.opsForValue().get(dto.getImageCodeKey());
        // 1.2.2 如果redis中的图片验证码为空,说明过期,要让用户重新获取
        RonghuaAssert.isNotBlank(imageCodeByRedis,ResponseCode.RESPONSE_CODE_40017);
        // 1.2.3 图片验证码不为空,才判断是否和前端的相等  判断图片验证码是否相等时,要忽略大小写的比对
        RonghuaAssert.isEqIgnoreCase(dto.getImageCode(),imageCodeByRedis,ResponseCode.RESPONSE_CODE_40016);

        // 1.3 校验手机号是否已注册
        User user = userMapper.loadByPhone(dto.getPhone());
        RonghuaAssert.isNull(user,ResponseCode.RESPONSE_CODE_40018);

        // 2 判断redis中该手机号存不存在验证码
        // 根据手机号和前缀,去redis中获取数据  value-> 手机验证码:发送时间
        sendSmsCode(BaseConstants.REGISTER_SMS_VERIFY_CODE_KEY,dto.getPhone());
    }

    private void sendSmsCode(String prefix,String phone) {
        String key = prefix+phone;
        String smsCodeByRedis = (String)redisTemplate.opsForValue().get(key);
        String smsCode = "";
        if(StringUtils.isNotBlank(smsCodeByRedis)){
            // 2.1 如果已存在,判断有没有过重发时间,如果没过重发时间,就返回错误信息,过了重发时间将验证码重新放入redis并设置过期时间,将验证码重新发给用户
            smsCode = smsCodeByRedis.split(":")[0];
            String sendTime = smsCodeByRedis.split(":")[1];
            // 2.1.1 判断有没有过重发时间  当前时间-发送时间 > 1分钟 过了重发时间   <1分钟 没过重发时间
            if(System.currentTimeMillis() - Long.parseLong(sendTime) < 60*1000){
                throw new BusinessException(ResponseCode.RESPONSE_CODE_40019);
            }
        }else{
            // 2.2 如果不存在,重新生成验证码,放入redis中,设置过期时间,将验证码发送给用户
            // 2.2.1 生成4位数的数字随机验证码
            smsCode = StrUtils.getRandomString(4);
        }
        // 2.2.2 将验证码和当前时间存入redis
        String value = smsCode+":"+System.currentTimeMillis();
        redisTemplate.opsForValue().set(key,value,5,TimeUnit.MINUTES);
        // 2.2.3 发送验证码给用户的手机号
        String content = "您的验证码为%s,请在5分钟内使用.";
        content = String.format(content,smsCode);
        System.out.println(content);
        //SmsUtil.sendSms(dto.getPhone(),content);
    }

    @Override
    public void bindSendSmsCode(Map<String, Object> map) {
        // 1 非空校验
        String phone = (String)map.get("phone");
        RonghuaAssert.isNotBlank(phone,ResponseCode.RESPONSE_CODE_500);

        // 2 发送手机验证码
        sendSmsCode(BaseConstants.BIND_SMS_VERIFY_CODE_KEY,phone);
    }
}
